package bio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * tcp服务
 * 传统阻塞io下的socket服务,BIO
 *
 * 1、并发模型：
 * 采用 "一个客户端一个线程" 的简单模型
 * 优点：实现简单，适用于少量客户端
 * 缺点：线程创建开销大，大量客户端时性能下降
 * 2、消息协议：
 * 基于文本行的协议（readLine()）
 * 客户端需发送换行符结束的消息
 * 3、资源管理：
 * 使用 try-with-resources 管理ServerSocket
 * 手动关闭clientSocket确保资源释放
 *
 *
 * 连接数少、处理时间长的场景
 * 编程复杂度	简单，逻辑清晰
 */
public class SocketServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("服务器启动，监听端口: 8080");

            while (true) {
                // 阻塞等待客户端连接
                /**
                 * accept()和read()方法会阻塞线程
                 */
                Socket clientSocket = serverSocket.accept();
                System.out.println("客户端连接: " + clientSocket.getInetAddress());

                // 为每个客户端创建新线程处理
                new Thread(() -> {
                    try (BufferedReader in = new BufferedReader(
                            new InputStreamReader(clientSocket.getInputStream()));
                         PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {

                        String inputLine;
                        while ((inputLine = in.readLine()) != null) {
                            /**
                             * BufferedReader 的 readLine() 方法是阻塞式的，会导致线程暂停执行直到满足以下条件之一：
                             * 读取到换行符（\n）或回车符（\r\n）
                             * 此时方法返回一行文本（不包含换行符）。
                             * 客户端关闭连接
                             * 返回 null，表示流结束。
                             * 发生异常
                             * 如网络中断、超时等，抛出 IOException。
                             *
                             * 阻塞时机：当客户端没有发送数据（或未发送换行符）时，readLine() 会让当前线程挂起，等待数据到达。
                             * 解除阻塞：只有当客户端发送数据并包含换行符，或关闭连接时，线程才会继续执行。
                             */
                            System.out.println("客户端消息: " + inputLine);
                            out.println("服务器响应: " + inputLine);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            clientSocket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        }
    }
}
